using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

namespace Xfinity.Rendering.Lighting
{
    public class SpotLight : ILight
    {
        #region Position
        private Vector3 position;

        /// <summary>
        /// Position.
        /// </summary>
        public Vector3 Position
        {
            [System.Diagnostics.DebuggerStepThroughAttribute]
            get { return position; }
            [System.Diagnostics.DebuggerStepThroughAttribute]
            set { position = value; }
        }
        #endregion
        #region Radiance
        private float radiance;

        /// <summary>
        /// Intensity.
        /// </summary>
        public float Radiance
        {
            [System.Diagnostics.DebuggerStepThroughAttribute]
            get { return radiance; }
            [System.Diagnostics.DebuggerStepThroughAttribute]
            set { radiance = value; }
        }
        #endregion
        #region Colour
        private Vector3 colour;

        /// <summary>
        /// Colour.
        /// </summary>
        public Vector3 Colour
        {
            [System.Diagnostics.DebuggerStepThroughAttribute]
            get { return colour; }
            [System.Diagnostics.DebuggerStepThroughAttribute]
            set { colour = value; }
        }
        #endregion
        #region Enabled
        private bool enabled;

        /// <summary>
        /// Enabled.
        /// </summary>
        public bool Enabled
        {
            [System.Diagnostics.DebuggerStepThroughAttribute]
            get { return enabled; }
            [System.Diagnostics.DebuggerStepThroughAttribute]
            set { enabled = value; }
        }
        #endregion
        #region Umbra
        private double umbra = 0.26179938779914943653855361527329;

        /// <summary>
        /// Umbra.
        /// </summary>
        public double Umbra
        {
            [System.Diagnostics.DebuggerStepThroughAttribute]
            get { return umbra; }
            [System.Diagnostics.DebuggerStepThroughAttribute]
            set
            {
                umbra = value;
                ci = Math.Cos(value);
                oocio = 1 / (ci - co);
            }
        }
        #endregion
        #region Penumbra
        private double penumbra = 0.52359877559829887307710723054658;

        /// <summary>
        /// Penumbra.
        /// </summary>
        public double Penumbra
        {
            [System.Diagnostics.DebuggerStepThroughAttribute]
            get { return penumbra; }
            [System.Diagnostics.DebuggerStepThroughAttribute]
            set
            {
                penumbra = value;
                co = Math.Cos(value);
                oocio = 1 / (ci - co);
            }
        }
        #endregion
        #region Direction
        private Vector3 direction;

        /// <summary>
        /// Direction.
        /// </summary>
        public Vector3 Direction
        {
            [System.Diagnostics.DebuggerStepThroughAttribute]
            get { return direction; }
            [System.Diagnostics.DebuggerStepThroughAttribute]
            set { direction = value; }
        }
        #endregion
        #region Power
        private double power = 1;

        /// <summary>
        /// Power.
        /// </summary>
        public double Power
        {
            [System.Diagnostics.DebuggerStepThroughAttribute]
            get { return power; }
            [System.Diagnostics.DebuggerStepThroughAttribute]
            set { power = value; }
        }
        #endregion

        private double ci, co, oocio;
        /// <summary>
        /// Gets the received colour at a point.
        /// </summary>
        /// <param name="point">The point.</param>
        /// <returns>The colour.</returns>
        public Vector3 GetColourAtPoint(Vector3 point)
        {
            Vector3 toPoint = point - position;
            toPoint.Normalize();
            float angle;
            Vector3.Dot(ref toPoint, ref direction, out angle);
            if (angle < co)
            {
                return Vector3.Zero;
            }

            float distance = toPoint.Length();
            float divisor = distance + radiance;
            Vector3 ranged = colour * ((radiance / (divisor * divisor)) * radiance * radiance);
            if (angle > ci)
            {
                return ranged;
            }

            return ranged * (float)(Math.Pow(angle - co, power) * oocio);
        }
    }
}
